﻿using SQLRunnerLib.Util;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using SQLRunnerLib.Project;
using System.IO;
using System;
using SQLServices.TransMgr;
using SQLRunnerLib.Exceptions;

namespace SQLUnitTests
{
    
    
    /// <summary>
    ///This is a test class for LineParserTest and is intended
    ///to contain all LineParserTest Unit Tests
    ///</summary>
    [TestClass()]
    public class LineParserTest
                : TestBase
    {

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get { return testContextInstance; }
            set { testContextInstance = value; }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        /// <summary>
        /// Test where only help arg provided
        ///</summary>
        [TestMethod()]
        public void HelpArgOnlyTest()
        {
            string[] args = new string[] { "-h" };
            LineParser lineParser = new LineParser(args);
            Assert.IsTrue(lineParser.ShowHelp);
            Assert.IsNull(lineParser.Project);
            Assert.AreEqual(lineParser.ServerName, string.Empty);
            Assert.AreEqual(lineParser.DatabaseName, string.Empty);
            Assert.AreEqual(lineParser.UserName, string.Empty);
            Assert.AreEqual(lineParser.Password, string.Empty);
        }

        /// <summary>
        /// For the command line to function the user must supply at least "-h" or a valid "-p:" argument
        ///</summary>
        [TestMethod()]
        [ExpectedException(typeof(ValidationException), "Minimum argument requirements have not been met.")]
        public void MinimumRequireParamsNotSuppliedTest()
        {
            string[] args = new string[] { "-s:lineServer", "-d:lineDB", "-u:username", "-w:pwd", "-t", "-v:test", "-m:p", "-e:1" };
            LineParser lineParser = new LineParser(args);

        }

        /// <summary>
        /// Test where project arg provided but file does not exist
        ///</summary>
        [TestMethod()]
        [ExpectedException(typeof(ValidationException), "Project file [C:\\filedoesnotexist.sqlrunner] does not exists")]
        public void ProjectFileDoesNotExistTest()
        {
            string[] args = new string[] { "-p:C:\\filedoesnotexist.sqlrunner" };
            LineParser lineParser = new LineParser(args);
        }

        /// <summary>
        /// Test where project arg provided but file not a valid project file
        ///</summary>
        ///<remarks>
        /// Having to do this with a Try Catch because we can't use Dynamic messages in the ExpectedException attribute.
        /// </remarks>
        [TestMethod()]
        public void ProjectFileNotInValidFormatTest()
        {
            bool exceptionWasCaught = false;
            string projectPath = CreateInvalidProjectFile("invlaidFile.sqlRunner");
            string[] args = new string[] { "-p:" + projectPath };
            try
            {
                LineParser lineParser = new LineParser(args);
            }
            catch (ValidationException ex)
            {
                exceptionWasCaught = true;
                Assert.AreEqual(string.Format("Project file [{0}] could not be read", Path.Combine(System.Environment.CurrentDirectory, "invlaidFile.sqlRunner")), ex.Message);
            }
            finally
            {
                // Cleanup
                File.Delete(projectPath);
            }

            Assert.IsTrue(exceptionWasCaught, "The exception must not have been raised");

        }

        /// <summary>
        /// Test where project arg provided but folder section empty
        ///</summary>
        [TestMethod()]
        public void ProjectFileWithNoFoldersTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithoutFolders(),"projectWithNoFolders.sqlRunner");
            string[] args = new string[] { "-p:" + projectPath };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNull(lineParser.Environment);
            Assert.AreEqual(lineParser.ServerName, string.Empty);
            Assert.AreEqual(lineParser.DatabaseName, string.Empty);
            Assert.AreEqual(lineParser.UserName, string.Empty);
            Assert.AreEqual(lineParser.Password, string.Empty);
            Assert.IsFalse(lineParser.ShowHelp);

            // Cleanup
            File.Delete(projectPath);
        }

        /// <summary>
        /// Test where project environment section empty and no connection info supplied
        /// </summary>
        [TestMethod()]
        public void ProjectFileWithNoEnvironmentsAndNoConnectionInfoSuppliedTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithoutEnvironment(), "projectWithNoEnvironments.sqlRunner");
            string[] args = new string[] { "-p:" + projectPath };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNull(lineParser.Environment);
            Assert.AreEqual(lineParser.ServerName, string.Empty);
            Assert.AreEqual(lineParser.DatabaseName, string.Empty);
            Assert.AreEqual(lineParser.UserName, string.Empty);
            Assert.AreEqual(lineParser.Password, string.Empty);
            Assert.IsFalse(lineParser.ShowHelp);

            // Cleanup
            File.Delete(projectPath);
        }

        /// <summary>
        /// Test where everything is provided
        /// </summary>
        [TestMethod()]
        public void EverythingProvidedTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), "projectWithNoEnvironments.sqlRunner");
            string[] args = new string[] { "-p:" + projectPath, "-s:lineServer", "-d:lineDB", "-u:username", "-w:pwd", "-h", "-t", "-v:test", "-m:p", "-e:1" };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNotNull(lineParser.Environment, "An environment is expected");
            Assert.AreEqual(lineParser.ServerName, "lineServer");
            Assert.AreEqual(lineParser.DatabaseName, "lineDB");
            Assert.AreEqual(lineParser.UserName, "username");
            Assert.AreEqual(lineParser.Password, "pwd");
            Assert.AreEqual(lineParser.ConnMgrType, ConnectionMgrType.PessimistConnMgr);
            Assert.IsTrue(lineParser.ShowHelp);
            Assert.AreEqual(lineParser.ErrorLevel, ErrorIndicator.AppFailure);

            // Cleanup
            File.Delete(projectPath);
        }


        //Test where project arg provided but environment section empty and no server provided
        //Test where project arg provided but environment section empty and no database provided

        //Test where project arg provided but environment section empty, not trusted, no username, no password
        //Test where project arg provided but environment section empty, not trusted, no username
        //Test where project arg provided but environment section empty, not trusted, no password

        //Test where project arg provided, environment section exists but not used and no connection info supplied
        //Test where project arg provided, environment section exists but not used.

        //Test where project arg provided, environment exists and is used. Environment: Valid.
        //Test where project arg provided, environment exists and is used. Environment: DB not found.
        //Test where project arg provided, environment exists and is used. Environment: Server not found.
        //Test where project arg provided, environment exists and is used. Environment: Credentials don't work.




        /// <summary>
        ///A test for LineParser Constructor
        ///</summary>
        [TestMethod()]
        public void InvalidParameterDoesNotStopExecutionTest()
        {
            string[] args = new string[] { "-h", "-z:Test" };
            LineParser lineParser = new LineParser(args);
            Assert.IsTrue(lineParser.ShowHelp);
        }

        //[TestMethod]
        //public void Connection_Details_Retrieved_From_EnvironmentSection()
        //{
        //    string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");
        //    string[] args = new string[] { "-p:" + projectPath };
        //    LineParser lineParser = new LineParser(args);
        //    var controller = new LineController();
        //    Assert.IsTrue(controller.TestValidateArgs(lineParser));
        //    Assert.AreEqual("serverName",lineParser.Environment.ServerName);
        //    Assert.AreEqual("dbName", lineParser.Environment.DatabaseName);
        //    Assert.IsTrue(lineParser.TrustedConnection);

        //    // Cleanup
        //    File.Delete(projectPath);
        //}

        //[TestMethod]
        //public void Connection_Details_Retrieved_From_CommandLine_TrustedConn()
        //{
        //    string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");
        //    string[] args = new string[] { "-p:" + projectPath, "-s:lineServer", "-d:lineDB" };
        //    LineParser lineParser = new LineParser(args);
        //    LineController controller = new LineController();
        //    Assert.IsTrue(controller.TestValidateArgs(lineParser));
        //    Assert.IsTrue(lineParser.ServerName.Equals("lineServer"));
        //    Assert.IsTrue(lineParser.DatabaseName.Equals("lineDB"));
        //    Assert.IsTrue(lineParser.TrustedConnection);

        //    // Cleanup
        //    File.Delete(projectPath);
        //}

        //[TestMethod]
        //public void Connection_Details_Retrieved_From_CommandLine_UserConn()
        //{
        //    string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");
        //    string[] args = new string[] { "-p:" + projectPath };
        //    LineParser lineParser = new LineParser(args);
        //    LineController controller = new LineController();
        //    Assert.IsTrue(controller.TestValidateArgs(lineParser));
        //    Assert.IsTrue(lineParser.ServerName.Equals("lineServer"));
        //    Assert.IsTrue(lineParser.DatabaseName.Equals("lineDB"));
        //    Assert.IsTrue(!lineParser.TrustedConnection);
        //    Assert.IsTrue(lineParser.UserName.Equals("username"));
        //    Assert.IsTrue(lineParser.Password.Equals("pwd"));

        //    // Cleanup
        //    File.Delete(projectPath);
        //}

        [TestMethod]
        public void MissingProjectArgumentTest()
        {
            string[] args = new string[] { "-h", "-s:lineServer", "-d:lineDB", "-u:username", "-w:pwd" };
            LineParser lineParser = new LineParser(args);

            Assert.AreEqual("lineServer", lineParser.ServerName);
            Assert.AreEqual("lineDB", lineParser.DatabaseName);
            Assert.AreEqual("username", lineParser.UserName);
            Assert.AreEqual("pwd", lineParser.Password);
            Assert.IsNull(lineParser.Environment);

        }

        [TestMethod]
        public void ProjectFileWithEnvironmentTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");

            string projectPathArg = "-p:" + projectPath;
            string[] args = new string[] {projectPathArg, "-v:test" };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNotNull(lineParser.Environment);
            Assert.AreEqual("test", lineParser.Environment.Name);

            // Cleanup
            File.Delete(projectPath);

        }

        /// <summary>
        /// The order in which arguments are supplied should not matter.  This test shows that environment can be before project.
        /// </summary>
        [TestMethod]
        public void ProjectFileWithEnvironmentArgOrderDoesNotMatterTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");

            string projectPathArg = "-p:" + projectPath;
            string[] args = new string[] { "-v:test", projectPathArg };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNotNull(lineParser.Environment);
            Assert.AreEqual("test", lineParser.Environment.Name);

            // Cleanup
            File.Delete(projectPath);

        }

        /// <summary>
        /// Tests where a project file is found but the environment name argument is not in the list of
        /// available environments.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ValidationException), "The environment name supplied [NonExistingEnv] does not exist in given project file.")]
        public void ProjectFileWithInvalidEnvironmentnameTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");

            string projectPathArg = "-p:" + projectPath;
            string[] args = new string[] { projectPathArg, "-v:NonExistingEnv" };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNull(lineParser.Environment);

            // Cleanup
            File.Delete(projectPath);
        }

        [TestMethod]
        public void InvalidConnectionManagerTest()
        {
            string projectPath = CreateProjectFile(CreateTestProjectWithEnvironment(), @"project.sqlrunner");

            string projectPathArg = "-p:" + projectPath;
            string[] args = new string[] { projectPathArg, "-v:test", "-m:a" };
            LineParser lineParser = new LineParser(args);
            Assert.IsNotNull(lineParser.Project);
            Assert.IsNotNull(lineParser.Environment);
            Assert.AreEqual("test", lineParser.Environment.Name);

            // Cleanup
            File.Delete(projectPath);

        }
    }
}
